package core

import (
	"fmt"
)

//区域边界

type AOIManager struct {
	MinX  int
	MaxX  int
	CntsX int
	MinY  int
	MaxY  int
	CntsY int
	grids map[int]*Grid
}

func NewAOIManager(minX, maxX, cutsX, minY, maxY, cntsY int) *AOIManager {
	aoiMgr := &AOIManager{
		MinX:  minX,
		MaxX:  maxX,
		CntsX: cutsX,
		MinY:  minY,
		MaxY:  maxY,
		CntsY: cntsY,
		grids: make(map[int]*Grid),
	}
	// 给AOI初始化区域的格子 进行编号
	/**
		0	1	2	3	4 --x
	0 	0	1	2	3	4
	1	5	6	7	8	9 		id = idy*cutsX + idx
	2	10	11	12	13	14
	3
	y
	*/
	for y := 0; y < cntsY; y++ {
		for x := 0; x < cutsX; x++ {
			// 格子编号：id = idy*cutsX + idx
			gid := y*cutsX + x
			// 初始化格子
			aoiMgr.grids[gid] = NewGrid(gid,
				aoiMgr.MinX+x*aoiMgr.gidWidth(),
				aoiMgr.MinX+(x+1)*aoiMgr.gidWidth(),
				aoiMgr.MinY+y*aoiMgr.gidLength(),
				aoiMgr.MinY+(y+1)*aoiMgr.gidLength())
		}
	}
	return aoiMgr
}

// 计算每个格子在x轴宽度
func (m *AOIManager) gidWidth() int {
	return (m.MaxX - m.MinX) / m.CntsX
}

// 计算每个格子在Y轴长度
func (m *AOIManager) gidLength() int {
	return (m.MaxY - m.MinY) / m.CntsY
}

// 通过 x,y坐标获取GID
func (m *AOIManager) GetGIDByPos(x, y float32) int {
	idx := (int(x) - m.MinX) / m.gidWidth()
	idy := (int(y) - m.MinY) / m.gidLength()
	return idy*m.CntsX + idx
}

// 根据格子GID获取周边九宫格的ID集合
func (m *AOIManager) GetSurroundGridsByGid(gID int) (grids []*Grid) {
	// 判断gID 是否在AOIManager中
	if _, ok := m.grids[gID]; !ok {
		return
	}
	// 将当前gid放入九宫格切片
	grids = append(grids, m.grids[gID])

	// 判断grids的左边是否有格子，右边是否有格子
	// 需要通过gId 得到当前格子的x轴编号 idx = id % cutsX
	idx := gID % m.CntsX

	// 判断 左边是否有格子 ？ x是否大于0，如果有放入gridsX集合中
	if idx > 0 {
		grids = append(grids, m.grids[gID-1])
	}

	if idx < m.CntsX-1 {
		// 右边的值
		grids = append(grids, m.grids[gID+1])
	}
	// 将x轴当前格子都取出，遍历，再看上下是否有值
	gridsX := make([]int, 0, len(grids))

	for _, v := range grids {
		gridsX = append(gridsX, v.GID)
	}
	// 遍历gidsX 集合中每个格子，看gid上面是否有格子，下面是否有格子
	for _, v := range gridsX {
		// 得到当前格子id的Y轴
		idy := v / m.CntsY
		// 判断上面是否有格子
		if idy > 0 {
			grids = append(grids, m.grids[v-m.CntsX])
		}
		// 判断下面是否有格子
		if idy < m.CntsY-1 {
			grids = append(grids, m.grids[v+m.CntsX])
		}
	}

	return
}

// 通过 x,y坐标获取周边九宫格信息
func (m *AOIManager) GetPidsByPos(x, y float32) (playIDs []int) {
	// 获取当前格子id
	gID := m.GetGIDByPos(x, y)
	// 通过GID获取九宫格信息
	grids := m.GetSurroundGridsByGid(gID)
	// 将九宫格信息的id 全部放到playIDs
	for _, grid := range grids {
		// 数据打散
		playIDs = append(playIDs, grid.GetPlayerIDs()...)
		fmt.Println("===>grid ID:", grid.GID, ",pids:", grid.GetPlayerIDs())
	}
	return
}

// 添加一个playerId到一个格子
func (m *AOIManager) AddPidToGrid(pID, gID int) {
	m.grids[gID].AddPlayer(pID)
}

// 移除一个格子的playerID
func (m *AOIManager) RemovePidFromGrid(pID, gID int) {
	m.grids[gID].Remove(pID)
}

// 通过GID获取全部的playerId
func (m *AOIManager) GetPidByGid(gID int) (playerIDs []int) {
	playerIDs = m.grids[gID].GetPlayerIDs()
	return
}

// 通过坐标将player添加到一个格子
func (m *AOIManager) AddToGridByPos(pId int, x, y float32) {
	gID := m.GetGIDByPos(x, y)
	grid := m.grids[gID]
	grid.AddPlayer(pId)
}

// 通过坐标把player从格子中删除
func (m *AOIManager) RemoveFromGridByPos(pId int, x, y float32) {
	gID := m.GetGIDByPos(x, y)
	grid := m.grids[gID]
	grid.Remove(pId)
}

// toString
func (m *AOIManager) String() string {
	s := fmt.Sprintf("AOIManager:\n MinX:%d,MaxX:%d,CutsX:%d,MinY:%d,MaxY:%d,CutsY:%d \n Grids in AIOManager;\n",
		m.MinX, m.MaxX, m.CntsX, m.MinY, m.MaxY, m.CntsY)

	for _, gid := range m.grids {
		s += fmt.Sprintln(gid)
	}
	return s
}
